﻿// Collect data from a W-network as it learns an input pattern

// Note that DLL reference order is very important
#r @"C:\Users\Mira\Source\Repos\Spinula\Debug\SpikingNeuronLib.dll"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsBaseLib\bin\Debug\SpikingAnalyticsBaseLib.dll"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsLib\bin\Debug\SpikingAnalyticsLib.dll"
#I @"C:\Users\Mira\Source\Repos\Spinula\packages\RProvider.1.0.12"
#load "RProvider.fsx"
#I @"C:\Users\Mira\Source\Repos\Spinula\packages\Deedle.1.0.0"
#load "Deedle.fsx"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingVisualisationRLib\bin\Debug\SpikingVisualisationRLib.dll"    // references Deedle
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsFrameLib\bin\Debug\SpikingAnalyticsFrameLib.dll"    // references Deedle

open System
open System.IO
open SpikingNeuronLib
open SpikingAnalyticsLib
open SpikingAnalyticsLib.PatternExtensions
open SpikingVisualisationRLib

let TrainWNetwork pathToOutputFolder backgroundFrequency =

    let verbose = true
    let runSeconds = 100
    let stimulusFrequency = 10

    let network =
        let specifier = CrossbarNetworkSpecifier.W_Network
        let hiDataResCollector =
            // membrane data: record the first 1000 samples from the run (one sample per msec)
            let numberOfMembraneSamples = 1000
            // weight data: record the entire run (one sample per msec)
            let numberOfWeightSamples = runSeconds * 1000
            let totalNeurons = specifier.TotalNeurons
            let totalConnections = specifier.Connections.Value.Count
            // collect membrane data for neurons: 0, 1, 2, 3, 4
            let selectedNeurons = [ for i in 0..totalNeurons-1 -> i ]
            // collect synaptic weight data for connections: 0, 1, 2, 3
            let selectedConnections = [ for i in 0..totalConnections-1 -> i ]
            let parameters = new OneMillisecTickDataCollectorParameters(selectedNeurons, totalNeurons, selectedConnections, totalConnections, numberOfMembraneSamples, numberOfWeightSamples)
            new OneMillisecTickDataCollector(parameters)
        CrossbarNetwork.CreateAdHocNetwork(specifier, Some(hiDataResCollector), verbose)

    // create an input pattern: repeated firing of both input layer neurons simultaneously (at time 0)
    let stimulus =
        let pattern =
            let times = [| 0; 0; |]
            let neurons = [| 0; 1; |]
            Pattern.FromFiringSequence(times, neurons)
        Stimulus.Create(stimulusFrequency, pattern)

    // run the network with this pattern and collect membrane and weight data
    network.Run(runSeconds, Some(stimulus :> IStimulus), backgroundFrequency)
    let hiResDataCollector = network.OneMillisecondEventCollector.Value

    // save the membrane potential data (V and U)
    let membraneDataPath = Path.Combine(pathToOutputFolder, "membraneData.txt")
    hiResDataCollector.SaveMembraneData(membraneDataPath)

    // show the membrane potential plots
    MillisecondResolutionDataVisualisation.ShowCollectedMembraneData(hiResDataCollector)

    // Create a new plot window
    VisualisationUtilities.NewWindow()

    // save the synaptic weight data (weight and derivative)
    let weightDataPath = Path.Combine(pathToOutputFolder, "weightData.txt")
    hiResDataCollector.SaveConnectionData(weightDataPath)

    // show the synaptic weight plots
    MillisecondResolutionDataVisualisation.ShowCollectedWeightData(hiResDataCollector)

let outputFolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
TrainWNetwork outputFolder 0
TrainWNetwork outputFolder 1
TrainWNetwork outputFolder 50
